import subprocess
import MySQLdb as sql
import logging
import logging.config
import time
import os
import sys

logging.config.fileConfig('/home/robert/update_log.txt')
logBinaries = logging.getLogger('binaries')
logOptimize = logging.getLogger('optimize')
logReleases = logging.getLogger('releases')
logBackup = logging.getLogger('backup')
logSQL = logging.getLogger('sql')
logMain = logging.getLogger('main')

PHP_PATH = '/usr/bin/php'
PY_PATH = '/usr/bin/python'
NN_DIR = '/var/www/newznab'
NN_UPDATE = 'misc/update_scripts'
NN_TESTING = 'misc/testing'

BINARIES_KEEPUP = 5
BACKFILL_DAYS = 300

RECALL = '/tmp/backup/recall.txt'

os.chdir(os.path.join(NN_DIR, NN_UPDATE))

MYSQL_DBNAME = 'newznab'
MYSQL_USER = 'root'
MYSQL_PASS = ''
MYSQL_HOST = 'localhost'

if not MYSQL_PASS:
    print 'No MySQL password entered.'
    sys.exit()

BACKLOG = """select COUNT(*) from releases r left join category c on c.ID = r.categoryID
             where (r.passwordstatus between -6 and -1)
              or (r.haspreview = -1 and c.disablepreview = 0);"""
BACKFILL = """update groups
              set backfill_target = backfill_target + 1
              where active = 1
               and backfill_target < {};""".format(BACKFILL_DAYS)

 # update commands

#updateBinaries = [PHP_PATH, os.path.join(NN_DIR, NN_UPDATE, 'update_binaries.php')]
updateBinaries = [PHP_PATH, os.path.join(NN_DIR, NN_UPDATE, 'update_binaries_threaded.php')]
updateReleases = [PHP_PATH, os.path.join(NN_DIR, NN_UPDATE, 'update_releases.php')]
updateBackfill = [PHP_PATH, os.path.join(NN_DIR, NN_UPDATE, 'backfill_threaded.php')]

OPTIMIZE = [ [PHP_PATH, os.path.join(NN_DIR, NN_TESTING, 'update_parsing.php')],
             [PHP_PATH, os.path.join(NN_DIR, NN_TESTING, 'removespecial.php')],
             [PHP_PATH, os.path.join(NN_DIR, NN_TESTING, 'update_cleanup.php')],
             [PHP_PATH, os.path.join(NN_DIR, NN_UPDATE, 'optimise_db.php')] ]


def sqlConnect():
    conn = None
    try:
        conn = sql.connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DBNAME)
    except sql.Error as e:
        logSQL.error('Error accessing db {}: {}'.format(MYSQL_DBNAME, e))
    else:
        logSQL.info('Connection successful.')
    return conn


def getBacklog():
    data = None
    conn = sqlConnect()
    if conn:
        cursor = conn.cursor()
        cursor.execute(BACKLOG)
        data = int(cursor.fetchone()[0])
        conn.close()
    return data


def setBackfillDate():
    conn = sqlConnect()
    if conn:
        cursor = conn.cursor()
        cursor.execute(BACKFILL)
        conn.close()


def getBinaries():
    logBinaries.info('Updating binaries.')
    try:
        subprocess.check_call(updateBinaries)
    except subprocess.CalledProcessError as e:
        logBinaries.error('Updating binaries failed: {}'.format(e))
        return False
    else:
        return True


def doReleases():
    logReleases.debug('Processing releases.')
    try:
        subprocess.check_call(updateReleases)
    except subprocess.CalledProcessError as e:
        logReleases.warning('Process update_releases crashed: {}'.format(e))
        return False
    else:
        logReleases.debug('Finished processing releases.')
        return True


def doBackfill():
    logBinaries.info('Doing backfill.')
    try:
        subprocess.check_call(updateBackfill)
    except subprocess.CalledProcessError as e:
        logBinaries.warning('Backfill error: {}'.format(e))
        return False
    else:
        logBinaries.info('Finished backfill.')
        return True


def doOptimize():
    logOptimize.info('Running optimizations')
    for cmd in OPTIMIZE:
        try:
            subprocess.check_call(cmd)
        except subprocess.CalledProcessError as e:
            logOptimize.warning('Optimization failed on command: {}\nError: {}'.format(cmd[-1]), e)
        else:
            logOptimize.debug('Optimization subtask complete: {}'.format(cmd[-1]))
    logOptimize.info('Optimization complete.')


def checkBackup():
    try:
        with open(RECALL, 'r') as f:
            b = f.read()
    except:
        return
    if 'stop_update' in b:
        time.sleep(3)
        with open(RECALL, 'a') as f:
            f.write('update_waiting\n')
        logBackup.info('Pause request received.  Waiting to resume.')
    while True:
        doSleep(600)
        if not os.path.exists(RECALL):
            logBackup.info('Recall file not found, resuming.')
            return


def doSleep(t):
    logMain.warning('Waiting {} seconds.'.format(t))
    time.sleep(t)


def main():
    conn = sqlConnect()
    if not conn:
        logMain.error('No connection found.  Aborting script.')
        sys.exit()
    else:
        conn.close()
    while True:
        if not getBinaries():
            sys.exit()
        print '\n'
        if not doReleases():
            sys.exit()
        print '\n'
        checkBackup()
        print '\n'
        if not doBackfill():
            sys.exit()
        print '\n'
        doReleases()
        print '\n'
        checkBackup()
        print '\n'
        counter = 0
        while getBacklog() > 100:
            doReleases()
            print '\n'
            counter += 1
            if counter > BINARIES_KEEPUP:
                getBinaries()
                print '\n'
                doReleases()
                print '\n'
                counter = 0
            checkBackup()
            print '\n'
        doOptimize()
        setBackfillDate()
        checkBackup()







if __name__ == '__main__':
    main()


